home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / pc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-24  |  27.8 KB  |  1,229 lines

  1. /* OS- and machine-dependent stuff for IBM-PC running MS-DOS and Turbo-C
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  * Mods by KO4KS
  4.  */
  5. #include <stdio.h>
  6. #include <conio.h>
  7. #include <dir.h>
  8. #include <dos.h>
  9. #include <io.h>
  10. #ifdef UNIX
  11. #include <sys/types.h>
  12. #endif
  13. #include <sys/stat.h>
  14. #include <string.h>
  15. #include <process.h>
  16. #include <fcntl.h>
  17. #include <alloc.h>
  18. #include <stdarg.h>
  19. #include <bios.h>
  20. #include "global.h"
  21. #include "config.h"
  22. #include "mbuf.h"
  23. #include "proc.h"
  24. #include "iface.h"
  25. #include "internet.h"
  26. #include "session.h"
  27. #include "tty.h"
  28. #include "socket.h"
  29. #include "smtp.h"
  30. #include "cmdparse.h"
  31. #include "dirutil.h"
  32. #include "pc.h"
  33.  
  34. #ifdef XSPAWN
  35. #include "xspawn.h"
  36. static int Xspawn = 1;
  37. #define SPAWNVP xspawnvp
  38. #else
  39. #define SPAWNVP spawnvp
  40. #endif
  41.  
  42. #define    CTLC    0x3
  43. #define    DEL    0x7f
  44.  
  45. static int kbchar __ARGS((void));
  46. extern int Curdisp;
  47. extern struct proc *Display;
  48. FILE *Rawterm;
  49. unsigned _stklen = 8192;
  50. volatile int Tick;
  51. static int32 Starttime;
  52. int32 Clock;
  53.  
  54. #ifdef MULTITASK
  55. int Background = 0;
  56. int Nokeys = 0;
  57. extern unsigned Minheap;
  58. #endif
  59. extern int Tracesession;
  60.  
  61. int Watchdog = 0;            /* Watch Dog off by default */
  62. int WDTick = 300*(1000 / MSPTICK);    /* 5 minutes watchdog timer */
  63. int WDCurr = 300*(1000 / MSPTICK);    /* Initial count down timer */
  64.  
  65. /* This flag is set by setirq() if IRQ 8-15 is used, indicating
  66.  * that the machine is a PC/AT with a second 8259 interrupt controller.
  67.  * If this flag is set, the interrupt return code in pcgen.asm will
  68.  * send an End of Interrupt command to the second 8259 as well as the
  69.  * first.
  70.  */
  71. int Isat;
  72.  
  73. static char Ttbuf[BUFSIZ];
  74. static char Tsbuf[BUFSIZ];
  75. static int saved_break;
  76.  
  77. /* Keyboard input buffer */
  78. #define    KBSIZE    256
  79. static struct {
  80.     char buf[KBSIZE];
  81.     char *wp;
  82.     char *rp;
  83.     int cnt;
  84. } Keyboard;
  85.  
  86. int
  87. am_i_an_AT()
  88. {
  89.     unsigned char *model_code = MK_FP(0xF000,0xFFFE);
  90.  
  91.     if(*model_code == 0xFC)
  92.         return 1;
  93.     else
  94.         return 0;
  95. }
  96.  
  97. /* Following code from Doug Crompton */
  98. /* define the error messages for trapping disk problems
  99.  */
  100. static char *crit_err_msg[] = {
  101.             "write protect",
  102.             "unknown unit",
  103.             "not ready",
  104.             "unknown command",
  105.             "data error (CRC)",
  106.             "bad request",
  107.             "seek error",
  108.             "unknown media type",
  109.             "sector not found",
  110.             "printer out of paper",
  111.             "write fault",
  112.             "read fault",
  113.             "general failure",
  114.             "reserved",
  115.             "reserved",
  116.             "invalid disk change"
  117.         };
  118.  
  119.  
  120. int
  121. errhandler(errval,ax,bp,si)
  122. int errval, ax, bp, si;
  123. {
  124.     char msg[80];
  125.     unsigned di;
  126.     int drive;
  127.     int errorno;
  128.  
  129.     di= _DI;
  130.  
  131. #ifndef DOSX286
  132.     if (ax < 0)
  133.         hardretn(3);
  134. #endif
  135.     drive = ax & 0x00FF;
  136.     errorno = di & 0x00FF;
  137.     sprintf(msg, "\r\nError: %s on drive %c\r\n$",
  138.                  crit_err_msg[errorno], 'A' + drive);
  139.     bdosptr(0x09,msg,0);
  140. #ifndef DOSX286
  141.     hardretn(3);
  142. #endif
  143.     return 0;   /* to please the compiler */
  144. }
  145.  
  146.  
  147. /* Called at startup time to set up console I/O, memory heap */
  148. void
  149. ioinit()
  150. {
  151.     /* Fail all I/O errors */
  152.     harderr(errhandler);
  153.  
  154.     /* Save these two file table entries for something more useful */
  155.     fclose(stdaux);
  156.     fclose(stdprn);
  157.     setbuf(stdout,Tsbuf);
  158.  
  159.     Rawterm = fopen("con","wb");
  160.     setbuf(Rawterm,Ttbuf);
  161.     /* this breaks tab expansion so you must use ANSI or NANSI */
  162.     ioctl(fileno(Rawterm), 1, (ioctl(fileno(Rawterm),0) & 0xff) | 0x20);
  163.     saved_break = getcbrk();
  164.     setcbrk(0);
  165.  
  166.     /* test to see if we're running on an AT class machine.
  167.      * Set Isat flag accordingly - N1BEE
  168.          */
  169.     Isat = am_i_an_AT();
  170.     Starttime = bioscnt();
  171.     /* Link timer handler into timer interrupt chain */
  172.     chtimer(btick);
  173.  
  174.     /* Find out what multitasker we're running under, if any */
  175.     chktasker();
  176.  
  177.     /* Initialize keyboard queue */
  178.     Keyboard.rp = Keyboard.wp = Keyboard.buf;
  179.  
  180. }
  181. /* Called just before exiting to restore console state */
  182. void
  183. iostop()
  184. {
  185.     struct iface *ifp,*iftmp;
  186.     void (**fp)();
  187.  
  188.     setbuf(Rawterm,NULLCHAR);
  189.     ioctl(fileno(Rawterm), 1, ioctl(fileno(Rawterm), 0) & 0xff & ~0x20);
  190.     setcbrk(saved_break);
  191.     for(ifp = Ifaces;ifp != NULLIF;ifp = iftmp){
  192.         iftmp = ifp->next;
  193.         if_detach(ifp);
  194.     }
  195.     /* Call list of shutdown functions */
  196.     for(fp = Shutdown;*fp != NULLVFP;fp++){
  197.         (**fp)();
  198.     }    
  199. }
  200. #ifdef SHELL
  201. /* Spawn subshell */
  202. int
  203. doshell(argc,argv,p)
  204. int argc;
  205. char *argv[];
  206. void *p;
  207. {
  208.     char *command;
  209.     int ret;
  210.  
  211. #ifdef MULTITASK
  212.     if(Background) {
  213.         if(!start_back())
  214.             return -1;
  215.         Nokeys++;
  216.     }
  217.     free(mallocw(Minheap)); /* Force heap/core break to reserve a heap */
  218. #endif
  219.  
  220.     if(argc == 1 || !stricmp(argv[1], "/c")) {
  221.         if((command = getenv("COMSPEC")) == NULLCHAR)
  222.             command = "COMMAND.COM";
  223. #ifdef XSPAWN
  224.         if (!Xspawn)
  225.             ret = spawnvp(P_WAIT,command,argv);
  226.         else
  227. #endif
  228.              ret = SPAWNVP(P_WAIT,command,argv);
  229.     } else {
  230. #ifdef XSPAWN
  231.         if (!Xspawn)
  232.             ret = spawnvp(P_WAIT,argv[1],(argv + 1));
  233.         else
  234. #endif
  235.             ret = SPAWNVP(P_WAIT,argv[1],(argv + 1));
  236.     }
  237.  
  238. #ifdef MULTITASK
  239.     if(Background) {
  240.         Nokeys--;
  241.         stop_back();
  242.     }
  243. #endif
  244.  
  245.     return ret;
  246. }
  247. #endif
  248.  
  249. #ifdef ALLCMD
  250. /* Spawn mailer as subshell */
  251. int
  252. dobmail(argc,argv,p)
  253. int argc;
  254. char *argv[];
  255. void *p;
  256. {
  257.     char *command;
  258.     int ret;
  259.  
  260. #ifdef MULTITASK
  261.     if(Background) {
  262.         if(!start_back())
  263.             return -1;
  264.         Nokeys++;
  265.     }
  266.     free(mallocw(Minheap));
  267. #endif
  268.  
  269.     if((command = getenv("MAILER")) == NULLCHAR)
  270.         command = "BM.EXE";
  271. #ifdef XSPAWN
  272.     if (!Xspawn)
  273.         ret = spawnvp(P_WAIT,command,argv);
  274.     else
  275. #endif
  276.         ret = SPAWNVP(P_WAIT,command,argv);
  277.  
  278. #ifdef MULTITASK
  279.     if(Background) {
  280.         Nokeys--;
  281.         stop_back();
  282.     }
  283. #endif
  284.  
  285.     smtptick(NULL);        /* tickle smtp to send any mail */
  286.     return ret;
  287. }
  288. #endif /*ALLCMD*/
  289.  
  290. #ifdef MULTITASK
  291. /* if multitask mode is set - allow NOS and shell/mail to share system time */
  292. dobackg(argc,argv,p)
  293. int argc;
  294. char *argv[];
  295. void *p;
  296. {
  297.     return setbool(&Background,"Multitasking DOS Shell ",argc,argv);
  298. }
  299. #endif
  300.  
  301. /* if watch-dog mode is set - make NOS reboot the system if it stalls */
  302. dowatchdog(argc,argv,p)
  303. int argc;
  304. char *argv[];
  305. void *p;
  306. {
  307.     return setbool(&Watchdog,"NOS Watch Dog",argc,argv);
  308. }
  309.  
  310. #ifdef XSPAWN
  311. doxspawn(argc,argv,p)
  312. int argc;
  313. char *argv[];
  314. void *p;
  315. {
  316. int retval;
  317.  
  318.     retval = setbool(&Xspawn,"XSPAWN mode",argc,argv);
  319.     _swap = (Xspawn ^ 1);
  320.     return retval;
  321. }
  322. #endif
  323.  
  324. /* Keyboard interrupt handler */
  325. void
  326. kbint()
  327. {
  328.     int sig = 0;
  329.     int c;
  330.  
  331. #ifdef MULTITASK
  332.     if(Background && Nokeys)
  333.         return;
  334. #endif
  335.     
  336.     while((c = kbraw()) != -1 && Keyboard.cnt < KBSIZE){
  337.         sig = 1;
  338.         *Keyboard.wp++ = c;
  339.         if(Keyboard.wp == &Keyboard.buf[KBSIZE])
  340.             Keyboard.wp = Keyboard.buf;
  341.         Keyboard.cnt++;
  342. #ifdef SCREENSAVER
  343.         sskick();
  344. #endif
  345.     }
  346.     if(sig){
  347.         psignal(&Keyboard,0);
  348.     }
  349. }
  350. static int
  351. kbchar()
  352. {
  353. char c;
  354. char i_state;
  355.  
  356. #ifdef MULTITASK
  357.     if(Background && Nokeys)
  358.         return -1;
  359. #endif
  360.  
  361.     i_state = dirps();
  362.     while(Keyboard.cnt == 0)
  363.         pwait(&Keyboard);
  364.     Keyboard.cnt--;
  365.     restore(i_state);
  366.     c = *Keyboard.rp++;
  367.     if(Keyboard.rp == &Keyboard.buf[KBSIZE])
  368.         Keyboard.rp = Keyboard.buf;
  369.     return uchar(c);
  370. }
  371. /* Flush the raw terminal output */
  372. void
  373. rflush()
  374. {
  375.     fflush(Rawterm);
  376. }
  377.  
  378. #ifdef MSDOS
  379. #ifdef ALLCMD
  380. struct funcstr {
  381.     unsigned char fkey;
  382.     char alloced;
  383.     char *fvalue;
  384. };
  385.  
  386. struct funcstr DFAR fkeys[] = {
  387.     15,0,NULLCHAR,    /* tab + shift */
  388.     59,1,NULLCHAR,  /* F1 */
  389.     60,1,NULLCHAR,  /* F2 */
  390.     61,1,NULLCHAR,  /* F3 */
  391.     62,1,NULLCHAR,  /* F4 */
  392.     63,0,NULLCHAR,    /* F5 */
  393.     64,0,NULLCHAR,    /* F6 */
  394.     65,0,NULLCHAR,    /* F7 */
  395.     66,0,NULLCHAR,    /* F8 */
  396.     67,0,NULLCHAR,    /* F9 */
  397.     68,0,NULLCHAR,    /* F10 */
  398.     71,1,NULLCHAR,    /* home*/
  399.     72,1,"\033[A",    /* up arrow*/
  400.     73,1,NULLCHAR,    /* pgup */
  401.     75,1,"\033[D",    /* left arrow */
  402.     77,1,"\033[C",    /* right arrow */
  403.     79,1,NULLCHAR,    /* end */
  404.     80,1,"\033[B",    /* down arrow */
  405.     81,1,NULLCHAR,    /* pgdn */
  406.     82,1,NULLCHAR,    /* ins */
  407.     83,1,NULLCHAR,    /* del */
  408.     84,0,NULLCHAR,    /* F1 + shift*/
  409.     85,0,NULLCHAR,    /* F2 + shift*/
  410.     86,0,NULLCHAR,    /* F3 + shift*/
  411.     87,0,NULLCHAR,    /* F4 + shift*/
  412.     88,0,NULLCHAR,    /* F5 + shift*/
  413.     89,0,NULLCHAR,    /* F6 + shift*/
  414.     90,0,NULLCHAR,    /* F7 + shift*/
  415.     91,0,NULLCHAR,    /* F8 + shift*/
  416.     92,0,NULLCHAR,    /* F9 + shift*/
  417.     93,0,NULLCHAR,    /* F10 + shift*/
  418.     94,0,NULLCHAR,    /* F1 + control*/
  419.     95,0,NULLCHAR,    /* F2 + control*/
  420.     96,0,NULLCHAR,    /* F3 + control*/
  421.     97,0,NULLCHAR,    /* F4 + control*/
  422.     98,0,NULLCHAR,    /* F5 + control*/
  423.     99,0,NULLCHAR,    /* F6 + control*/
  424.     100,0,NULLCHAR,    /* F7 + control*/
  425.     101,0,NULLCHAR,    /* F8 + control*/
  426.     102,0,NULLCHAR,    /* F9 + control*/
  427.     103,0,NULLCHAR,    /* F10 + control*/
  428.     104,0,NULLCHAR,    /* F1 + alt*/
  429.     105,0,NULLCHAR,    /* F2 + alt*/
  430.     106,0,NULLCHAR,    /* F3 + alt*/
  431.     107,0,NULLCHAR,    /* F4 + alt*/
  432.     108,0,NULLCHAR,    /* F5 + alt*/
  433.     109,0,NULLCHAR,    /* F6 + alt*/
  434.     110,0,NULLCHAR,    /* F7 + alt*/
  435.     111,0,NULLCHAR,    /* F8 + alt*/
  436.     112,0,NULLCHAR,    /* F9 + alt*/
  437.     113,0,NULLCHAR,    /* F10 + alt*/
  438.     114,0,NULLCHAR,    /* PrtSc + ctl*/
  439.     117,0,NULLCHAR,    /* end  + ctl */
  440.     118,0,NULLCHAR,    /* pgup + ctl */
  441.     119,0,NULLCHAR,    /* home + ctl */
  442.     132,0,NULLCHAR,    /* pgdn + ctl */
  443.     133,0,NULLCHAR, /* F11 */
  444.     134,0,NULLCHAR, /* F12 */
  445.     135,0,NULLCHAR, /* F11 + shift */
  446.     136,0,NULLCHAR, /* F12 + shift */
  447.     137,0,NULLCHAR, /* F11 + control */
  448.     138,0,NULLCHAR, /* F11 + control */
  449.     139,0,NULLCHAR, /* F11 + alt */
  450.     140,0,NULLCHAR, /* F11 + alt */
  451.       0,0,NULLCHAR
  452. };
  453.  
  454. char Leftover = 0;
  455. char *Nextkey;
  456. #endif /*ALLCMD*/
  457. #endif /*MSDOS*/
  458.  
  459. /* Read characters from the keyboard, translating them to "real" ASCII.
  460.  * If none are ready, block. The F-10 key is special; translate it to -2.
  461.  */
  462. #ifdef ALLCMD
  463. int
  464. kbread()
  465. {
  466.     int c,i,j;
  467.  
  468.     if((c = Leftover) != 0)  {
  469.         Leftover = *Nextkey++;
  470.         return c;
  471.     }
  472.     if((c = kbchar()) == 0){
  473.         /* Lead-in to a special char */
  474.         c = kbchar();
  475.         switch(c){
  476.         case 3:        /* NULL (bizzare!) */
  477.             c = 0;
  478.             break;
  479.     case 72:    /* UP ARROW key (used as previous history command) */
  480.             if(Current == Command) {   
  481.                 c = UPARROW;
  482.                 break;
  483.             }
  484.             goto all;
  485.     case 80:    /* DOWN ARROW key (used as next history command) */
  486.             if(Current == Command) {
  487.                 c = DNARROW;
  488.                 break;
  489.             }
  490.             goto all;
  491.         case 68:    /* F-10 key (used as command-mode escape) */
  492.             if(fkeys[10].fvalue == NULLCHAR){
  493.                 c = -2;
  494.                 break;
  495.             }
  496.                 goto all;
  497.         case 82:   /* INSERT key (used as status line toggle) */
  498.             if(fkeys[19].fvalue == NULLCHAR){
  499.                 c = -105;
  500.                 break;
  501.             }
  502.             goto all;
  503.         case 83:   /* DELETE key (used as flow mode toggle) */
  504.             if(fkeys[20].fvalue == NULLCHAR){
  505.                 c = -106;
  506.                 break;
  507.             }
  508.             goto all;
  509.         case 71:   /* HOME key (used to kick this session) */
  510.             if(fkeys[11].fvalue == NULLCHAR){
  511.                 c = -107;
  512.                 break;
  513.             }
  514.             goto all;
  515.         case 79:   /* END key (used to kill this session) */
  516.             if(fkeys[16].fvalue == NULLCHAR){
  517.                 c = -108;
  518.                 break;
  519.             }
  520.             goto all;
  521.         case 73:   /* PGUP key (used to toggle to previous session) */
  522.             if(fkeys[13].fvalue == NULLCHAR){
  523.                 c = -109;
  524.                 break;
  525.             }
  526.             goto all;
  527.         case 81:   /* PGDN key (used to toggle to next session) */
  528.             if(fkeys[18].fvalue == NULLCHAR){
  529.                 c = -110;
  530.                 break;
  531.             }
  532.             goto all;
  533.         default:    /* Dunno what it is */
  534. all:
  535.             if(c > 58 && c < 68) {  /* F1 to F9 */
  536.                 if(fkeys[c-58].fvalue == NULLCHAR) {
  537.                     c = (c - 56) * -1; /* NO fkey defined - WG7J */
  538.                     break;
  539.                 }
  540.             }
  541.             for(i=0;(j = fkeys[i].fkey) != 0;i++)
  542.                 if(j == c) {
  543.                     Nextkey = fkeys[i].fvalue;
  544.                     if(Nextkey == NULLCHAR) {
  545.                         c = -1;
  546.                         return c;
  547.                     }
  548.                     /* If first char of fvalue is '~'
  549.                      * switch to command session.
  550.                      */
  551.                     if((c = *Nextkey++) == '~') {
  552.                         c = -2;
  553.                         Leftover = *Nextkey++;
  554.                     } else {
  555.                         if(c != 0)
  556.                             Leftover = *Nextkey++;
  557.                         else
  558.                             c = -1;
  559.                     }
  560.                     return c;
  561.                 }
  562.             c = -1;
  563.         }
  564.     }
  565.     return c;
  566. }
  567. #else /*ALLCMD*/
  568.  
  569. int
  570. kbread()
  571. {
  572.         int c;
  573.  
  574.         if((c = kbchar()) == 0){
  575.                 /* Lead-in to a special char */
  576.                 c = kbchar();
  577.                 if(Current == Command) {    /* Check for command recall */
  578.                     if(c == 72)     /* UP arrow */
  579.                         return UPARROW;
  580.                     if(c == 80)     /* DOWN arrow */
  581.                         return DNARROW;
  582.                 }
  583.                 switch(c){
  584.                 case 3:         /* NULL (bizzare!) */
  585.                         c = 0;
  586.                         break;
  587.                 case 68:        /* F-10 key (used as command-mode escape) */
  588.                         c = -2;
  589.                         break;
  590.                 case 83:        /* DEL key */
  591.                         c = 0x7f;
  592.                         break;
  593.                 default:        /* Dunno what it is */
  594.                     if(c > 58 && c < 68)    /* F1 to F9 */
  595.                         c = (c - 56) * -1;
  596.                     else
  597.                         c = -1;
  598.                 }
  599.         }
  600.         return c;
  601. }
  602.  
  603. #endif /*ALLCMD*/
  604.  
  605. #ifdef    MSDOS
  606. #ifdef ALLCMD
  607. int
  608. dofkey(argc,argv,p)
  609. int argc;
  610. char *argv[];
  611. void *p;
  612. {
  613.     int c,i,j;
  614.     char *q, *r;
  615.     char str[100];
  616.  
  617.     if(argc == 1) {
  618.        tprintf("key   num    key    num    key    num    key    num   key    num\n");
  619.        tprintf("f1     59    sf1     84    cf1     94    af1    104   pgup    73\n");
  620.        tprintf("f2     60    sf2     85    cf2     95    af2    105   pgdn    81\n");
  621.        tprintf("f3     61    sf3     86    cf3     96    af3    106   home    71\n");
  622.        tprintf("f4     62    sf4     87    cf4     97    af4    107   end     79\n");
  623.        tprintf("f5     63    sf5     88    cf5     98    af5    108   arup    72\n");
  624.        tprintf("f6     64    sf6     89    cf6     99    af6    109   ardn    80\n");
  625.        tprintf("f7     65    sf7     90    cf7    100    af7    110   ar l    75\n");
  626.        tprintf("f8     66    sf8     91    cf8    101    af8    111   ar r    77\n");
  627.        tprintf("f9     67    sf9     92    cf9    102    af9    112   ins     82\n");
  628.        tprintf("f10    68    sf10    93    cf10   103    af10   113   del     83\n");
  629.        tprintf("f11   133    sf11   135    cf11   137    af11   139   stab    15\n");
  630.        tprintf("f12   134    sf12   136    cf12   138    af12   140   cprtsc 114\n");
  631.        tprintf("cpgup 132    cpgdn  118    chome  119    cend   117\n");
  632.        tprintf("usage: fkey <key number> [<value> | \"string\"]\n");
  633.        return 0;
  634.     }
  635.  
  636.     c = atoi(argv[1]);
  637.     if(c == 0 || c > 255) {
  638.         tprintf("fkey number out of range.\n");
  639.         return 1;
  640.     }
  641.  
  642.     for(j = 0;(i = fkeys[j].fkey) != 0; j++)
  643.         if(i == c) 
  644.             break;
  645.  
  646.     if(i == 0){
  647.         tprintf("fkey number not found\n");
  648.         return 1;
  649.     }
  650.  
  651.     if(argc == 2) {
  652.         q = fkeys[j].fvalue;
  653.         r = str;
  654.         if(q == NULLCHAR)
  655.             tprintf("fkey %d has no assigned value.\n",c);
  656.         else {
  657.             while(*q)
  658.                 if(*q < ' ') { /* This is ASCII dependent !! */
  659.                     *r++ = '^';
  660.                     *r++ = *q++ + 0x40;
  661.                 } else
  662.                     *r++ = *q++;
  663.             *r = '\0';
  664.             tprintf("fkey = %s\n",str);
  665.         }
  666.         return 0;
  667.     }
  668.  
  669.     if(argc == 3) {
  670.         if(fkeys[j].alloced)
  671.             fkeys[j].alloced = 0;
  672.         else
  673.             if(fkeys[j].fvalue != NULLCHAR)
  674.                 free(fkeys[j].fvalue);
  675.  
  676.         r = str;
  677.         q = argv[2];
  678.         while(*q){
  679.             if(*q == '^'){    /* ^ gives control char next */
  680.                 q++;
  681.                 if(*q == '^') {
  682.                     *r++ = *q++; /* No, he wants a ^ */
  683.                 } else {
  684.                     *r++ = *q++ & 0x1f;
  685.                 }
  686.             } else
  687.                 *r++ = *q++;
  688.         }
  689.         *r = '\0';
  690.         fkeys[j].fvalue = strdup(str);
  691.     }
  692.     return 0;
  693. }
  694. #endif /*ALLCMD*/
  695. #endif /*MSDOS*/
  696.  
  697. /* Install hardware interrupt handler.
  698.  * Takes IRQ numbers from 0-7 (0-15 on AT) and maps to actual 8086/286 vectors
  699.  * Note that bus line IRQ2 maps to IRQ9 on the AT
  700.  */
  701. int
  702. setirq(irq,handler)
  703. unsigned irq;
  704. INTERRUPT (*handler)();
  705. {
  706.     /* Set interrupt vector */
  707.     if(irq < 8){
  708. #ifdef XSPAWN
  709.         addvect(8+irq, CURRENT);    /* tell XSPAWN to ignore this vector */
  710. #endif
  711.         setvect(8+irq,handler);
  712.     } else if(irq < 16){
  713.         Isat = 1;
  714. #ifdef XSPAWN
  715.         addvect(0x70 + irq - 8, CURRENT);    /* tell XSPAWN to this one */
  716. #endif
  717.         setvect(0x70 + irq - 8,handler);
  718.     } else {
  719.         return -1;
  720.     }
  721.     return 0;
  722. }
  723. /* Return pointer to hardware interrupt handler.
  724.  * Takes IRQ numbers from 0-7 (0-15 on AT) and maps to actual 8086/286 vectors
  725.  */
  726. INTERRUPT
  727. (*getirq(irq))()
  728. unsigned int irq;
  729. {
  730.     /* Set interrupt vector */
  731.     if(irq < 8){
  732.         return getvect(8+irq);
  733.     } else if(irq < 16){
  734.         return getvect(0x70 + irq - 8);
  735.     } else {
  736.         return NULLVIFP;
  737.     }
  738. }
  739. /* Disable hardware interrupt */
  740. int
  741. maskoff(irq)
  742. unsigned irq;
  743. {
  744.     if(irq < 8){
  745.         setbit(0x21,(char)(1<<irq));
  746.     } else if(irq < 16){
  747.         irq -= 8;
  748.         setbit(0xa1,(char)(1<<irq));
  749.     } else {
  750.         return -1;
  751.     }
  752.     return 0;
  753. }
  754. /* Enable hardware interrupt */
  755. int
  756. maskon(irq)
  757. unsigned irq;
  758.  {
  759.     if(irq < 8){
  760.         clrbit(0x21,(char)(1<<irq));
  761.     } else if(irq < 16){
  762.         irq -= 8;
  763.         clrbit(0xa1,(char)(1<<irq));
  764.     } else {
  765.         return -1;
  766.     }
  767.     return 0;
  768. }
  769. /* Return 1 if specified interrupt is enabled, 0 if not, -1 if invalid */
  770. int
  771. getmask(irq)
  772. unsigned irq;
  773. {
  774.     if(irq < 8)
  775.         return (inportb(0x21) & (1 << irq)) ? 0 : 1;
  776.     else if(irq < 16){
  777.         irq -= 8;
  778.         return (inportb(0xa1) & (1 << irq)) ? 0 : 1;
  779.     } else
  780.         return -1;
  781. }
  782. /* Called from assembler stub linked to BIOS interrupt 1C, called on each
  783.  * hardware clock tick. Signal a clock tick to the timer process.
  784.  */
  785. void
  786. ctick()
  787. {
  788.     if(Watchdog)
  789.         if(WDCurr-- == 0)
  790.             sysreset();    
  791.     Tick++;
  792. #ifdef notdef
  793.     Clock++;    /* Keep system time */
  794. #endif
  795.     psignal(&Tick,1);
  796. }
  797. /* Called from the timer process on every tick. NOTE! This function
  798.  * can NOT be called at interrupt time because it calls the BIOS
  799.  */
  800. void
  801. pctick()
  802. {
  803.     long t;
  804.     static long oldt;    /* Value of bioscnt() on last call */
  805.     static long days;    /* # of times bioscnt() has rolled over */
  806.  
  807.     /* Update the time-since-boot */
  808.     t = bioscnt();
  809.  
  810.     if(t < oldt)
  811.         days++;    /* bioscnt has rolled past midnight */
  812.     oldt = t;
  813.     Clock = (days * 0x1800b0) + t - Starttime;
  814. }
  815.  
  816. /* Set bit(s) in I/O port */
  817. void
  818. setbit(port,bits)
  819. unsigned port;
  820. char bits;
  821. {
  822.     outportb(port,(char)inportb(port)|bits);
  823. }
  824. /* Clear bit(s) in I/O port */
  825. void
  826. clrbit(port,bits)
  827. unsigned port;
  828. char bits;
  829. {
  830.     outportb(port,(char)(inportb(port) & ~bits));
  831. }
  832. /* Set or clear selected bit(s) in I/O port */
  833. void
  834. writebit(port,mask,val)
  835. unsigned port;
  836. char mask;
  837. int val;
  838. {
  839.     register char x;
  840.  
  841.     x = inportb(port);
  842.     if(val)
  843.         x |= mask;
  844.     else
  845.         x &= ~mask;
  846.     outportb(port,x);
  847. }
  848. /* Convert a pointer to a long integer */
  849. long
  850. ptol(p)
  851. void *p;
  852. {
  853.     long x;
  854.  
  855.     x = FP_OFF(p);
  856. #ifdef    LARGEDATA
  857.     x |= (long)FP_SEG(p) << 16;
  858. #endif
  859.     return x;
  860. }
  861. void *
  862. ltop(l)
  863. long l;
  864. {
  865.     register unsigned seg,offset;
  866.  
  867.     seg = l >> 16;
  868.     offset = l;
  869.     return MK_FP(seg,offset);
  870. }
  871. #ifdef notdef    /* Assembler versions in pcgen.asm */
  872. /* Multiply a 16-bit multiplier by an arbitrary length multiplicand.
  873.  * Product is left in place of the multiplicand, and the carry is
  874.  * returned
  875.  */
  876. int16
  877. longmul(multiplier,n,multiplicand)
  878. int16 multiplier;
  879. int n;                /* Number of words in multiplicand[] */
  880. register int16 *multiplicand;    /* High word is in multiplicand[0] */
  881. {
  882.     register int i;
  883.     unsigned long pc;
  884.     int16 carry;
  885.  
  886.     carry = 0;
  887.     multiplicand += n;
  888.     for(i=n;i != 0;i--){
  889.         multiplicand--;
  890.         pc = carry + (unsigned long)multiplier * *multiplicand;
  891.         *multiplicand = pc;
  892.         carry = pc >> 16;
  893.         }
  894.     }
  895.     return carry;
  896. }
  897. /* Divide a 16-bit divisor into an arbitrary length dividend using
  898.  * long division. The quotient is returned in place of the dividend,
  899.  * and the function returns the remainder.
  900.  */
  901. int16
  902. longdiv(divisor,n,dividend)
  903. int16 divisor;
  904. int n;                /* Number of words in dividend[] */
  905. register int16 *dividend;    /* High word is in dividend[0] */
  906. {
  907.     /* Before each division, remquot contains the 32-bit dividend for this
  908.      * step, consisting of the 16-bit remainder from the previous division
  909.      * in the high word plus the current 16-bit dividend word in the low
  910.      * word.
  911.      *
  912.      * Immediately after the division, remquot contains the quotient
  913.      * in the low word and the remainder in the high word (which is
  914.      * exactly where we need it for the next division).
  915.      */
  916.     unsigned long remquot;
  917.     register int i;
  918.  
  919.     if(divisor == 0)
  920.         return 0;    /* Avoid divide-by-zero crash */
  921.     remquot = 0;
  922.     for(i=0;i<n;i++,dividend++){
  923.         remquot |= *dividend;
  924.         if(remquot == 0)
  925.             continue;    /* Avoid unnecessary division */
  926. #ifdef    __TURBOC__
  927.         /* Use assembly lang routine that returns both quotient
  928.          * and remainder, avoiding a second costly division
  929.          */
  930.         remquot = divrem(remquot,divisor);
  931.         *dividend = remquot;    /* Extract quotient in low word */
  932.         remquot &= ~0xffffL;    /* ... and mask it off */
  933. #else
  934.         *dividend = remquot / divisor;
  935.         remquot = (remquot % divisor) << 16;
  936. #endif
  937.     }
  938.     return remquot >> 16;
  939. }
  940. #endif
  941. void
  942. sysreset()
  943. {
  944.     void (*foo) __ARGS((void));
  945.  
  946.     foo = MK_FP(0xffff,0);    /* FFFF:0000 is hardware reset vector */
  947.     (*foo)();
  948. }
  949.  
  950. void stowit __ARGS((size_t index, int save, unsigned char attr));
  951. extern unsigned char SCREENwidth, SCREENlength;
  952. extern int STATLINE;
  953. extern struct session *ScreenOwner;        /* Session currently displayed */
  954.  
  955. void
  956. newscreen(sp)
  957. struct session *sp;
  958. {
  959.     if(sp != NULLSESSION)    {
  960.         sp->screen = callocw(1,sizeof(struct screen));
  961.         sp->screen->statline = STATLINE;
  962.     }
  963. }
  964. void
  965. freescreen(sp)
  966. struct session *sp;
  967. {
  968.     if(sp == NULLSESSION || sp->screen == NULLSCREEN)
  969.         return;
  970.     if((sp->screen->save != NULLCHAR) && sp->screen->save != (char *) 1)
  971.         free(sp->screen->save);
  972.     free((char *)sp->screen);
  973. }
  974.  
  975.  
  976. /* Save specified session screen and resume console screen */
  977. void
  978. swapscreen(old,new)
  979. struct session *old,*new;
  980. {
  981. struct text_info tr;
  982. unsigned char attr;
  983.     
  984.     if(old == new)
  985.         return;    /* Nothing to do */
  986.  
  987.     fflush(Rawterm);
  988.     gettextinfo(&tr);
  989.     if(old != NULLSESSION){
  990.         /* Save old screen */
  991.         if(old->screen->save == NULLCHAR)
  992. #ifndef TNOS
  993.             old->screen->save
  994.              = malloc(2*tr.screenheight*tr.screenwidth);
  995. #else
  996.             old->screen->save = (char *) 1;
  997. #endif
  998.         if(old->screen->save != NULLCHAR){
  999.             if(old->split){
  1000.                 window(1,1,SCREENwidth,SCREENlength);
  1001.                 tr.winbottom = SCREENlength;
  1002.             }
  1003. #ifndef TNOS
  1004.             gettext(tr.winleft,tr.wintop,tr.winright,
  1005.              tr.winbottom,old->screen->save);
  1006. #else
  1007.             stowit(old->index, 1, 0);    // save it
  1008. #endif
  1009.         }
  1010.         old->screen->row = tr.cury;
  1011.         old->screen->col = tr.curx;
  1012.         old->screen->attr = tr.attribute;
  1013.     }
  1014.     if(new != NULLSESSION){
  1015.         /* Load new screen */
  1016.         if(new->screen->save != NULLCHAR){
  1017.             if(new->split){
  1018.                 window(1,1,SCREENwidth,SCREENlength - 2);
  1019. #ifndef TNOS
  1020.                 clrscr();
  1021. #endif
  1022.             } else {
  1023.                 window(1,1,SCREENwidth,SCREENlength);
  1024. #ifndef TNOS
  1025.                 clrscr();
  1026. #endif
  1027.             }
  1028. #ifndef TNOS
  1029.             puttext(tr.winleft,tr.wintop,tr.winright,
  1030.              tr.winbottom,new->screen->save);
  1031.             /* Free the memory (saves 4K on a continuous basis) */
  1032.             free(new->screen->save);
  1033. #else
  1034.             setscreens ((new->screen->attr >> 4) & 0x07, new->screen->attr & 0x0f, 0);
  1035.             stowit (new->index, 0, new->screen->attr);    // retrieve it
  1036.             new->screen->attr &= 0x7f;    // remove color change bit
  1037. #endif
  1038. //            if (STATLINE && (Current == Command))
  1039.                 window (1,1 + new->screen->statline,SCREENwidth,SCREENlength - (new->split * 2));
  1040.             gotoxy(new->screen->col,new->screen->row);
  1041.             textattr (new->screen->attr);
  1042.             new->screen->save = NULLCHAR;
  1043.         } else {
  1044.             window(1,1,SCREENwidth,SCREENlength);
  1045.             clrscr();    /* Start with a fresh slate */
  1046.             if(new->split){
  1047.                 new->tsavex = 1;
  1048.                 new->tsavey = 1;
  1049.                 new->bsavex = 1;
  1050.                 new->bsavey = SCREENlength - 1;
  1051.                 window(1,SCREENlength - 1,SCREENwidth,SCREENlength);
  1052.                 gettextinfo(&tr);
  1053.                 attr = ((tr.attribute & 0x0f) << 4) + ((tr.attribute & 0x70) >> 4);
  1054.                 textattr (attr);
  1055.                 clrscr ();
  1056.                 cputs("_\b");
  1057.                 window(1,1 + new->screen->statline,SCREENwidth,SCREENlength - 2 - new->screen->statline);
  1058.                 textattr (tr.attribute);
  1059.                 }
  1060.             else
  1061.                 window(1,1 + new->screen->statline,SCREENwidth,SCREENlength - new->screen->statline);
  1062. //            if (STATLINE)
  1063. //                displayStatLine (-1);
  1064.         }
  1065.     }
  1066.     ScreenOwner = new;
  1067.     displayStatLine (0, 1);
  1068.     alert(Display,1);    /* Wake him up */
  1069. }
  1070.  
  1071. void
  1072. display(i,v1,v2)
  1073. int i;
  1074. void *v1;
  1075. void *v2;
  1076. {
  1077.     int c;
  1078.     struct session *sp;
  1079.  
  1080.     /* This is very tricky code. Because the value of "Current" can
  1081.      * change any time we do a pwait, we have to be careful to detect
  1082.      * any change and go back and start again.
  1083.      */
  1084.     for(;;){
  1085.         sp = Current;
  1086.  
  1087.         if(sp->morewait){
  1088.             pwait(&sp->row);
  1089.             if(sp != Current || sp->row <= 0){
  1090.                 /* Current changed value, or the user
  1091.                  * hasn't really hit a key
  1092.                  */
  1093.                 continue;
  1094.             }
  1095.             /* Erase the prompt */
  1096.             fprintf(Rawterm,"\b\b\b\b\b\b\b\b        \b\b\b\b\b\b\b\b");
  1097.             rflush ();
  1098.         }
  1099.         sp->morewait = 0;
  1100.         if((c = rrecvchar(sp->output)) == -1){
  1101.             /* the alert() in swapscreen will cause this to
  1102.              * return -1 when current changes
  1103.              */
  1104.             pwait(NULL);    /* Prevent a nasty loop */
  1105.             continue;
  1106.         }
  1107. #ifdef SCREENSAVER
  1108.         sskick ();
  1109. #endif
  1110.         if(sp->split){
  1111.             if(c == 0x0a){
  1112.                 cputs(Eol);
  1113.                 clreol();
  1114.             } else
  1115.                 putch(c);
  1116.         } else {
  1117.             putc(c,Rawterm);
  1118.         }
  1119.         /* Fix by Ron Murray, vk6zjm */
  1120.         if(sp->record != NULLFILE)      /* Don't save CR if ascii mode */
  1121.             if (c != '\r' || sockmode(sp->output, -1) != SOCK_ASCII)
  1122.                 putc(c,sp->record);
  1123. #ifdef notdef
  1124.         if(sp->record != NULLFILE)
  1125.             putc(c,sp->record);
  1126. #endif
  1127.         if(sp->flowmode && c == '\n' && --sp->row <= 0){
  1128.             fprintf(Rawterm,"--More--");
  1129.             sp->morewait = 1;
  1130.         }
  1131.     }
  1132. }
  1133. /* Return time since startup in milliseconds. If the system has an
  1134.  * 8254 clock chip (standard on ATs and up) then resolution is improved
  1135.  * below 55 ms (the clock tick interval) by reading back the instantaneous
  1136.  * value of the counter and combining it with the global clock tick counter.
  1137.  * Otherwise 55 ms resolution is provided.
  1138.  *
  1139.  * Reading the 8254 is a bit tricky since a tick could occur asynchronously
  1140.  * between the two reads. The tick counter is examined before and after the
  1141.  * hardware counter is read. If the tick counter changes, try again.
  1142.  * Note: the hardware counter counts down from 65536.
  1143.  */
  1144. int32
  1145. msclock()
  1146. {
  1147.     int32 hi;
  1148.     int16 lo;
  1149.     int16 count[4]; /* extended (48-bit) counter of timer clocks */
  1150.  
  1151.     if(!Isat)
  1152.         return Clock * MSPTICK;
  1153.  
  1154.     do {
  1155.         hi = Clock + Tick;
  1156.         lo = clockbits();
  1157.     } while(hi != Clock + Tick); /* Make sure a tick didn't just occur */
  1158.  
  1159.     count[0] = 0;
  1160.     count[1] = hi >> 16;
  1161.     count[2] = hi;
  1162.     count[3] = -lo;
  1163.     longmul(11,4,count);    /* The ratio 11/13125 is exact */
  1164.     longdiv(13125,4,count);
  1165.     return ((long)count[2] << 16) + count[3];
  1166. }
  1167. /* Return clock in seconds */
  1168. int32
  1169. secclock()
  1170. {
  1171.     int32 hi;
  1172.     int16 lo;
  1173.     int16 count[4];    /* extended (48-bit) counter of timer clocks */
  1174.  
  1175.     if(!Isat)
  1176.         return Clock * MSPTICK / 1000L;
  1177.  
  1178.     do {
  1179.         hi = Clock + Tick;
  1180.         lo = clockbits();
  1181.     } while(hi != Clock + Tick); /* Make sure a tick didn't just occur */
  1182.  
  1183.     count[0] = 0;
  1184.     count[1] = hi >> 16;
  1185.     count[2] = hi;
  1186.     count[3] = -lo;
  1187.     longmul(11,4,count);    /* The ratio 11/13125 is exact */
  1188.     longdiv(13125,4,count);
  1189.     longdiv(1000,4,count);
  1190.     return ((long)count[2] << 16) + count[3];
  1191. }
  1192.  
  1193. int
  1194. doisat(argc,argv,p)
  1195. int argc;
  1196. char *argv[];
  1197. void *p;
  1198. {
  1199.     return setbool(&Isat,"AT/386 mode",argc,argv);
  1200. }
  1201.  
  1202. /* Directly read BIOS count of time ticks. This is used instead of
  1203.  * calling biostime(0,0L). The latter calls BIOS INT 1A, AH=0,
  1204.  * wich resets the midnight overflow flag, losing days on the clock.
  1205.  */
  1206. long
  1207. bioscnt()
  1208. {
  1209.     int i_state;
  1210.     long rval;
  1211.  
  1212.     i_state = dirps();
  1213.     rval = * (long DFAR *)MK_FP(0x40,0x6c);
  1214.     restore(i_state);
  1215.     return rval;
  1216. }
  1217.  
  1218. /* same as getenv(), but return "" instead of NULL when it does not exist */
  1219. char *getnenv (name)
  1220. char *name;
  1221. {
  1222.     char *rv;
  1223.  
  1224.     if ((rv = getenv(name)) == NULL)
  1225.          rv = "";            /* NULL replaced by "" */
  1226.  
  1227.     return rv;
  1228. }
  1229.